#pragma once
#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Value.hpp>
#include <etcd/Watcher.hpp>
#include <functional>
#include "spdlogger.hpp"

/*
    对etcd-cpp-apiv3二次封装：
    1、服务注册客户端类：向注册中心发起k-v注册

    2、服务发现客户端类: 发现注册中心的服务，提供两个回调函数put_cb和del_cb，
       由用户自定义设置，当监听到事件的时候执行相应的回调
*/
namespace ns_etcd
{
    // 服务注册客户端类
    class Registry
    {
        const static int default_ttl = 3;

    public:
        Registry(const std::string &etcd_url):
            _client(std::make_shared<etcd::Client>(etcd_url)),           // 初始化客户端对象
            _keepalive(_client->leasekeepalive(default_ttl).get()), // 获取保活对象
            _lease_id(_keepalive->Lease())                          // 获取租约id
        {
        }

        // 服务注册
        bool registry(const std::string &key, const std::string &value) const
        {
            etcd::Response resp = _client->put(key, value, _lease_id).get();
            if (!resp.is_ok())
            {
                LOG_ERROR("the registry is fail：{}", resp.error_message());
                return false;
            }
            return true;
        }

    private:
        shared_ptr<etcd::Client> _client;
        shared_ptr<etcd::KeepAlive> _keepalive;
        int64_t _lease_id;
    };


    // 服务发现客户端类
    class Discovery
    {
    private:
        using discovery_cb_t = std::function<void(const std::string& key, const std::string& value)>;

        void callback(const etcd::Response &resp)
        {
            if (!resp.is_ok())
            {
                LOG_ERROR("the event listener is incorrect：{}", resp.error_message());
                return;
            }
            etcd::Events evs = resp.events();
            for (auto &ev : evs)
            {
                if (ev.event_type() == etcd::Event::EventType::PUT) // 新增或修改
                {
                    _put_cb(ev.kv().key(), ev.kv().as_string()); // 用户自定义行为
                }
                else if (ev.event_type() == etcd::Event::EventType::DELETE_) // 删除
                {
                    _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string()); // 用户自定义行为
                }
            }
        }

    public:
        Discovery(const std::string &etcd_url, const std::string &base_dir, const discovery_cb_t &put_cb, discovery_cb_t del_cb):
            _client(std::make_shared<etcd::Client>(etcd_url)), // 客户端对象
            _put_cb(put_cb), // 用户自定义行为
            _del_cb(del_cb) // 用户自定义行为
        {
            // 1、发现注册中心的所有服务
            etcd::Response resp = _client->ls(base_dir).get();
            if (!resp.is_ok())
            {
                LOG_WARN("the discovery is error：{}", resp.error_message());
            }
            size_t sz = resp.keys().size();
            for (int i = 0; i < sz; i++)
            {
                LOG_INFO("{}提供服务：{}", resp.value(i).as_string(), resp.key(i));
            }

            // 2、监听注册中心的服务
            _watcher = std::make_shared<etcd::Watcher>(*_client.get(), base_dir, 
                std::bind(&ns_etcd::Discovery::callback, this, placeholders::_1), true);            
            _watcher->Wait();
        }

    private:
        shared_ptr<etcd::Client> _client;
        shared_ptr<etcd::Watcher> _watcher;
        discovery_cb_t _put_cb; // 监听到put事件的回调函数(用户自定义)
        discovery_cb_t _del_cb; // 监听到get事件的回调函数(用户自定义)
    };
}